use std::env;
-use cargo::core::Workspace;
-use cargo::ops::{self, CompileOptions, MessageFormat};
-use cargo::util::important_paths::{find_root_manifest_for_wd};
+use cargo::ops::{self};
+use cargo::ops::cargo_check::{Options, with_check_env};
use cargo::util::{CliResult, Config};
-#[derive(RustcDecodable)]
-pub struct Options {
- flag_package: Vec<String>,
- flag_jobs: Option<u32>,
- flag_features: Vec<String>,
- flag_all_features: bool,
- flag_no_default_features: bool,
- flag_target: Option<String>,
- flag_manifest_path: Option<String>,
- flag_verbose: u32,
- flag_quiet: Option<bool>,
- flag_color: Option<String>,
- flag_message_format: MessageFormat,
- flag_release: bool,
- flag_lib: bool,
- flag_bin: Vec<String>,
- flag_example: Vec<String>,
- flag_test: Vec<String>,
- flag_bench: Vec<String>,
- flag_locked: bool,
- flag_frozen: bool,
-}
pub const USAGE: &'static str = "
Check a local package and all of its dependencies for errors
pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
debug!("executing; cmd=cargo-check; args={:?}",
env::args().collect::<Vec<_>>());
- config.configure(options.flag_verbose,
- options.flag_quiet,
- &options.flag_color,
- options.flag_frozen,
- options.flag_locked)?;
-
- let root = find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())?;
-
- let opts = CompileOptions {
- config: config,
- jobs: options.flag_jobs,
- target: options.flag_target.as_ref().map(|t| &t[..]),
- features: &options.flag_features,
- all_features: options.flag_all_features,
- no_default_features: options.flag_no_default_features,
- spec: ops::Packages::Packages(&options.flag_package),
- mode: ops::CompileMode::Check,
- release: options.flag_release,
- filter: ops::CompileFilter::new(options.flag_lib,
- &options.flag_bin,
- &options.flag_test,
- &options.flag_example,
- &options.flag_bench),
- message_format: options.flag_message_format,
- target_rustdoc_args: None,
- target_rustc_args: None,
- };
- let ws = Workspace::new(&root, config)?;
- ops::compile(&ws, &opts)?;
- Ok(None)
+ with_check_env(options, config, |ws, opts| {
+ ops::compile(ws, opts)?;
+ Ok(None)
+ })
}
MultiShell { out: out, err: err, verbosity: verbosity }
}
+ // Create a quiet, basic shell from supplied writers.
+ pub fn from_write(out: Box<Write + Send>, err: Box<Write + Send>) -> MultiShell {
+ let config = ShellConfig { color_config: ColorConfig::Never, tty: false };
+ let out = Shell { terminal: NoColor(out), config: config.clone() };
+ let err = Shell { terminal: NoColor(err), config: config };
+ MultiShell {
+ out: out,
+ err: err,
+ verbosity: Verbosity::Quiet,
+ }
+ }
+
pub fn out(&mut self) -> &mut Shell {
&mut self.out
}
--- /dev/null
+use core::Workspace;
+use ops::{self, CompileOptions, MessageFormat};
+use util::important_paths::{find_root_manifest_for_wd};
+use util::{CliResult, Config};
+
+#[derive(RustcDecodable)]
+pub struct Options {
+ flag_package: Vec<String>,
+ flag_jobs: Option<u32>,
+ flag_features: Vec<String>,
+ flag_all_features: bool,
+ flag_no_default_features: bool,
+ flag_target: Option<String>,
+ flag_manifest_path: Option<String>,
+ flag_verbose: u32,
+ flag_quiet: Option<bool>,
+ flag_color: Option<String>,
+ flag_message_format: MessageFormat,
+ flag_release: bool,
+ flag_lib: bool,
+ flag_bin: Vec<String>,
+ flag_example: Vec<String>,
+ flag_test: Vec<String>,
+ flag_bench: Vec<String>,
+ flag_locked: bool,
+ flag_frozen: bool,
+}
+
+impl Options {
+ pub fn default() -> Options {
+ Options {
+ flag_package: vec![],
+ flag_jobs: None,
+ flag_features: vec![],
+ flag_all_features: false,
+ flag_no_default_features: false,
+ flag_target: None,
+ flag_manifest_path: None,
+ flag_verbose: 0,
+ flag_quiet: None,
+ flag_color: None,
+ flag_message_format: MessageFormat::Human,
+ flag_release: false,
+ flag_lib: false,
+ flag_bin: vec![],
+ flag_example: vec![],
+ flag_test: vec![],
+ flag_bench: vec![],
+ flag_locked: false,
+ flag_frozen: false,
+ }
+ }
+}
+
+
+pub fn with_check_env<F>(options: Options, config: &Config, f: F) -> CliResult<Option<()>>
+ where F: FnOnce(&Workspace, &CompileOptions) -> CliResult<Option<()>>
+{
+ config.configure(options.flag_verbose,
+ options.flag_quiet,
+ &options.flag_color,
+ options.flag_frozen,
+ options.flag_locked)?;
+
+ let root = find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())?;
+
+ let opts = CompileOptions {
+ config: config,
+ jobs: options.flag_jobs,
+ target: options.flag_target.as_ref().map(|t| &t[..]),
+ features: &options.flag_features,
+ all_features: options.flag_all_features,
+ no_default_features: options.flag_no_default_features,
+ spec: ops::Packages::Packages(&options.flag_package),
+ mode: ops::CompileMode::Check,
+ release: options.flag_release,
+ filter: ops::CompileFilter::new(options.flag_lib,
+ &options.flag_bin,
+ &options.flag_test,
+ &options.flag_example,
+ &options.flag_bench),
+ message_format: options.flag_message_format,
+ target_rustdoc_args: None,
+ target_rustc_args: None,
+ };
+
+ let ws = Workspace::new(&root, config)?;
+ f(&ws, &opts)
+}
use core::{Source, Package, Target};
use core::{Profile, TargetKind, Profiles, Workspace, PackageIdSpec};
-use ops::{self, BuildOutput};
+use ops::{self, BuildOutput, Executor, DefaultExecutor};
use util::config::Config;
use util::{CargoResult, profile};
pub fn compile<'a>(ws: &Workspace<'a>, options: &CompileOptions<'a>)
-> CargoResult<ops::Compilation<'a>> {
+ compile_with_exec(ws, options, &mut DefaultExecutor)
+}
+
+pub fn compile_with_exec<'a, E: Executor>(ws: &Workspace<'a>,
+ options: &CompileOptions<'a>,
+ exec: &mut E)
+ -> CargoResult<ops::Compilation<'a>> {
for member in ws.members() {
for key in member.manifest().warnings().iter() {
options.config.shell().warn(key)?
}
}
- compile_ws(ws, None, options)
+ compile_ws(ws, None, options, exec)
}
-pub fn compile_ws<'a>(ws: &Workspace<'a>,
- source: Option<Box<Source + 'a>>,
- options: &CompileOptions<'a>)
- -> CargoResult<ops::Compilation<'a>> {
+pub fn compile_ws<'a, E: Executor>(ws: &Workspace<'a>,
+ source: Option<Box<Source + 'a>>,
+ options: &CompileOptions<'a>,
+ exec: &mut E)
+ -> CargoResult<ops::Compilation<'a>> {
let CompileOptions { config, jobs, target, spec, features,
all_features, no_default_features,
release, mode, message_format,
&resolve_with_overrides,
config,
build_config,
- profiles)?
+ profiles,
+ exec)?
};
ret.to_doc_test = to_builds.iter().map(|&p| p.clone()).collect();
use core::{SourceId, Source, Package, Dependency, PackageIdSpec};
use core::{PackageId, Workspace};
-use ops::{self, CompileFilter};
+use ops::{self, CompileFilter, DefaultExecutor};
use sources::{GitSource, PathSource, SourceConfigMap};
use util::{CargoResult, ChainError, Config, human, internal};
use util::{Filesystem, FileLock};
check_overwrites(&dst, pkg, &opts.filter, &list, force)?;
}
- let compile = ops::compile_ws(&ws, Some(source), opts).chain_error(|| {
+ let compile = ops::compile_ws(&ws, Some(source), opts, &mut DefaultExecutor).chain_error(|| {
if let Some(td) = td_opt.take() {
// preserve the temporary directory, so the user can inspect it
td.into_path();
use core::{SourceId, Package, PackageId, Workspace, Source};
use sources::PathSource;
use util::{self, CargoResult, human, internal, ChainError, Config, FileLock};
-use ops;
+use ops::{self, DefaultExecutor};
pub struct PackageOpts<'cfg> {
pub config: &'cfg Config,
mode: ops::CompileMode::Build,
target_rustdoc_args: None,
target_rustc_args: None,
- })?;
+ }, &mut DefaultExecutor)?;
Ok(())
}
fn update_local(&self) -> CargoResult<()> {
match self.local {
LocalFingerprint::MtimeBased(ref slot, ref path) => {
- let meta = fs::metadata(path).chain_error(|| {
- internal(format!("failed to stat `{}`", path.display()))
- })?;
- let mtime = FileTime::from_last_modification_time(&meta);
- *slot.0.lock().unwrap() = Some(mtime);
+ if let Ok(meta) = fs::metadata(path) {
+ let mtime = FileTime::from_last_modification_time(&meta);
+ *slot.0.lock().unwrap() = Some(mtime);
+ }
}
LocalFingerprint::Precalculated(..) => return Ok(())
}
use core::{Package, PackageId, PackageSet, Target, Resolve};
use core::{Profile, Profiles, Workspace};
use core::shell::ColorConfig;
-use util::{self, CargoResult, ProcessBuilder, human, machine_message};
+use util::{self, CargoResult, ProcessBuilder, ProcessError, human, machine_message};
use util::{Config, internal, ChainError, profile, join_paths, short_hash};
use self::job::{Job, Work};
pub type PackagesToBuild<'a> = [(&'a Package, Vec<(&'a Target, &'a Profile)>)];
+/// A glorified callback for executing calls to rustc. Rather than calling rustc
+/// directly, we'll use an Executor, giving clients an opportunity to intercept
+/// the build calls.
+pub trait Executor: Clone + Send + 'static {
+ fn init(&mut self, cx: &Context);
+ /// If execution succeeds, the ContinueBuild value indicates whether Cargo
+ /// should continue with the build process for this package.
+ fn exec(&self, cmd: ProcessBuilder, id: &PackageId) -> Result<ContinueBuild, ProcessError>;
+}
+
+/// A DefaultExecutorcalls rustc without doing anything else. It is Cargo's
+/// default behaviour.
+#[derive(Copy, Clone)]
+pub struct DefaultExecutor;
+
+impl Executor for DefaultExecutor {
+ fn init(&mut self, _cx: &Context) {}
+
+ fn exec(&self, cmd: ProcessBuilder, _id: &PackageId) -> Result<ContinueBuild, ProcessError> {
+ cmd.exec()?;
+ Ok(ContinueBuild::Continue)
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ContinueBuild {
+ Continue,
+ Stop,
+}
+
// Returns a mapping of the root package plus its immediate dependencies to
// where the compiled libraries are all located.
-pub fn compile_targets<'a, 'cfg: 'a>(ws: &Workspace<'cfg>,
- pkg_targets: &'a PackagesToBuild<'a>,
- packages: &'a PackageSet<'cfg>,
- resolve: &'a Resolve,
- config: &'cfg Config,
- build_config: BuildConfig,
- profiles: &'a Profiles)
- -> CargoResult<Compilation<'cfg>> {
+pub fn compile_targets<'a, 'cfg: 'a, E: Executor>(ws: &Workspace<'cfg>,
+ pkg_targets: &'a PackagesToBuild<'a>,
+ packages: &'a PackageSet<'cfg>,
+ resolve: &'a Resolve,
+ config: &'cfg Config,
+ build_config: BuildConfig,
+ profiles: &'a Profiles,
+ exec: &mut E)
+ -> CargoResult<Compilation<'cfg>> {
let units = pkg_targets.iter().flat_map(|&(pkg, ref targets)| {
let default_kind = if build_config.requested_target.is_some() {
Kind::Target
// part of this, that's all done next as part of the `execute`
// function which will run everything in order with proper
// parallelism.
- compile(&mut cx, &mut queue, unit)?;
+ compile(&mut cx, &mut queue, unit, exec)?;
}
// Now that we've figured out everything that we're going to do, do it!
Ok(cx.compilation)
}
-fn compile<'a, 'cfg: 'a>(cx: &mut Context<'a, 'cfg>,
- jobs: &mut JobQueue<'a>,
- unit: &Unit<'a>) -> CargoResult<()> {
+fn compile<'a, 'cfg: 'a, E: Executor>(cx: &mut Context<'a, 'cfg>,
+ jobs: &mut JobQueue<'a>,
+ unit: &Unit<'a>,
+ exec: &mut E) -> CargoResult<()> {
if !cx.compiled.insert(*unit) {
return Ok(())
}
let work = if unit.profile.doc {
rustdoc(cx, unit)?
} else {
- rustc(cx, unit)?
+ rustc(cx, unit, exec)?
};
let link_work1 = link_targets(cx, unit)?;
let link_work2 = link_targets(cx, unit)?;
// Be sure to compile all dependencies of this target as well.
for unit in cx.dep_targets(unit)?.iter() {
- compile(cx, jobs, unit)?;
+ compile(cx, jobs, unit, exec)?;
}
Ok(())
}
-fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult<Work> {
+fn rustc<E: Executor>(cx: &mut Context, unit: &Unit, exec: &mut E) -> CargoResult<Work> {
let crate_types = unit.target.rustc_crate_types();
let mut rustc = prepare_rustc(cx, crate_types, unit)?;
.flat_map(|i| i)
.map(|s| s.to_string())
.collect::<Vec<_>>();
+
+ exec.init(cx);
+ let exec = exec.clone();
+
return Ok(Work::new(move |state| {
// Only at runtime have we discovered what the extra -L and -l
// arguments are for native libraries, so we process those here. We
}
state.running(&rustc);
- if json_messages {
+ let cont = if json_messages {
rustc.exec_with_streaming(
&mut |line| if !line.is_empty() {
Err(internal(&format!("compiler stdout is not empty: `{}`", line)))
}
Ok(())
},
- ).map(|_| ())
+ ).map(|_| ()).chain_error(|| {
+ human(format!("Could not compile `{}`.", name))
+ })?;
+ ContinueBuild::Continue
} else {
- rustc.exec()
- }.chain_error(|| {
- human(format!("Could not compile `{}`.", name))
- })?;
+ exec.exec(rustc, &package_id).chain_error(|| {
+ human(format!("Could not compile `{}`.", name))
+ })?
+ };
- if do_rename && real_name != crate_name {
- let dst = &filenames[0].0;
- let src = dst.with_file_name(dst.file_name().unwrap()
- .to_str().unwrap()
- .replace(&real_name, &crate_name));
- if !has_custom_args || src.exists() {
- fs::rename(&src, &dst).chain_error(|| {
- internal(format!("could not rename crate {:?}", src))
- })?;
+ if cont == ContinueBuild::Continue {
+ if do_rename && real_name != crate_name {
+ let dst = &filenames[0].0;
+ let src = dst.with_file_name(dst.file_name().unwrap()
+ .to_str().unwrap()
+ .replace(&real_name, &crate_name));
+ if !has_custom_args || src.exists() {
+ fs::rename(&src, &dst).chain_error(|| {
+ internal(format!("could not rename crate {:?}", src))
+ })?;
+ }
}
- }
- if !has_custom_args || fs::metadata(&rustc_dep_info_loc).is_ok() {
- info!("Renaming dep_info {:?} to {:?}", rustc_dep_info_loc, dep_info_loc);
- fs::rename(&rustc_dep_info_loc, &dep_info_loc).chain_error(|| {
- internal(format!("could not rename dep info: {:?}",
- rustc_dep_info_loc))
- })?;
- fingerprint::append_current_dir(&dep_info_loc, &cwd)?;
+ if !has_custom_args || fs::metadata(&rustc_dep_info_loc).is_ok() {
+ info!("Renaming dep_info {:?} to {:?}", rustc_dep_info_loc, dep_info_loc);
+ fs::rename(&rustc_dep_info_loc, &dep_info_loc).chain_error(|| {
+ internal(format!("could not rename dep info: {:?}",
+ rustc_dep_info_loc))
+ })?;
+ fingerprint::append_current_dir(&dep_info_loc, &cwd)?;
+ }
}
if json_messages {
pub use self::cargo_clean::{clean, CleanOptions};
-pub use self::cargo_compile::{compile, compile_ws, CompileOptions};
+pub use self::cargo_compile::{compile, compile_with_exec, compile_ws, CompileOptions};
pub use self::cargo_compile::{CompileFilter, CompileMode, MessageFormat, Packages};
pub use self::cargo_read_manifest::{read_manifest,read_package,read_packages};
pub use self::cargo_rustc::{compile_targets, Compilation, Kind, Unit};
pub use self::cargo_rustc::Context;
pub use self::cargo_rustc::{BuildOutput, BuildConfig, TargetConfig};
+pub use self::cargo_rustc::{Executor, DefaultExecutor, ContinueBuild};
pub use self::cargo_run::run;
pub use self::cargo_install::{install, install_list, uninstall};
pub use self::cargo_new::{new, init, NewOptions, VersionControl};
pub use self::resolve::{resolve_ws, resolve_ws_precisely, resolve_with_previous};
pub use self::cargo_output_metadata::{output_metadata, OutputMetadataOptions, ExportInfo};
+pub mod cargo_check;
mod cargo_clean;
mod cargo_compile;
mod cargo_doc;
rustdoc: LazyCell::new(),
extra_verbose: Cell::new(false),
frozen: Cell::new(false),
- locked: Cell::new(false),
+ locked: Cell::new(false),
}
}
}
}
-fn homedir(cwd: &Path) -> Option<PathBuf> {
+pub fn homedir(cwd: &Path) -> Option<PathBuf> {
let cargo_home = env::var_os("CARGO_HOME").map(|home| {
cwd.join(home)
});
pub use self::cfg::{Cfg, CfgExpr};
-pub use self::config::Config;
+pub use self::config::{Config, homedir};
pub use self::dependency_queue::{DependencyQueue, Fresh, Dirty, Freshness};
pub use self::errors::{CargoResult, CargoError, ChainError, CliResult};
pub use self::errors::{CliError, ProcessError, CargoTestError};